package com.qianfeng.smartplatform.service.impl;/*
 *@Description:
 *@author:赵健
 *@Date:zjzzz 2022/9/7 16:50
 */

import com.qianfeng.smartplatform.constans.ResultCode;
import com.qianfeng.smartplatform.dto.UserDto;
import com.qianfeng.smartplatform.event.LoginFailEvent;
import com.qianfeng.smartplatform.event.LoginSuccessEvent;
import com.qianfeng.smartplatform.exceptions.AddDataException;
import com.qianfeng.smartplatform.exceptions.FindDataException;
import com.qianfeng.smartplatform.mapper.UserMapper;
import com.qianfeng.smartplatform.pojo.SysUserInfo;
import com.qianfeng.smartplatform.service.UserService;
import com.qianfeng.smartplatform.utils.MyStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private ApplicationContext context;

    @Autowired
    private UserMapper userMapper;

    @Override
    public void addUser(UserDto userDto) {
//需要查询一下数据是不是存在,存在需要提醒客户端,账号已经存在
        List<SysUserInfo> userInfoList = userMapper.findByUserNameOrPhoneOrEmail(userDto.getUsername(), userDto.getPhone(), userDto.getEmail());

        Assert.isTrue(userInfoList.size()==0,()->{
            throw new AddDataException( "账号已经存在", ResultCode.USERNAME_ALREADY_EXIST);
        });

        //手机号的格式,邮箱的格式
        //对数据进行校验,转换到SysUserInfo对象上面
        SysUserInfo sysUserInfo = new SysUserInfo();
        //拷贝数据,要求属性名一样
        // sysUserInfo.setUsername(userDto.getUsername());
        BeanUtils.copyProperties(userDto,sysUserInfo);
        //将密码转成MD5
        //随机生成一个十位的字符串
        String salt = MyStringUtils.createRandomString(10);
        //盐必须要保存,否则下次得到的结果不一样的话就无法校验数据了
        sysUserInfo.setPwdSalt(salt);
        //我们真正的密码是 salt+password+salt
        String passwordMD5 = DigestUtils.md5DigestAsHex((salt + sysUserInfo.getPassword() + salt).getBytes(StandardCharsets.UTF_8));
        //将密码替换为MD5值
        sysUserInfo.setPassword(passwordMD5);
        //自己注册的就是自己,管理员添加的就写管理员的账号
        sysUserInfo.setCreateBy(sysUserInfo.getUsername());
        sysUserInfo.setRemark("普通用户");
        userMapper.addUser(sysUserInfo);
    }

    @Override
    public SysUserInfo findUserByName(String userName) {
        SysUserInfo user = userMapper.findUserByName(userName);
        return user;
    }

    @Override
    public SysUserInfo login(String userName, String password) {
        SysUserInfo sysUserInfo = findUserByName(userName);
        //将用户传递过来的密码和我们的盐一起计算出一个md5值,这个值如果和数据库查询出来的一样,则代表登录成功
        String passwordMD5 = DigestUtils.md5DigestAsHex((sysUserInfo.getPwdSalt() + password + sysUserInfo.getPwdSalt()).getBytes(StandardCharsets.UTF_8));
        Assert.isTrue(passwordMD5.equals(sysUserInfo.getPassword()),()->{
            context.publishEvent(new LoginFailEvent(null,userName));
            throw new FindDataException("用户名密码错误", ResultCode.USERNAME_PASSWORD_ERROR);
        });
        //更新日志不是当前业务的核心操作,属于辅助操作,并且成功与否不能影响前面的登录操作,所以当前操作可以放在异步中执行
        //怎么搞一个异步?
        //虽然我们的需求中并没有展示登录时间等操作,但是要记住,我们几乎所有和登录,修改等相关的操作,在表中都有对应的时间列
        //我们需要更新用户的数据,登录的时间和ip
        //   String ip = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getRemoteHost();
        // userMapper.updateLoginDataByUserId(sysUserInfo.getUId(),ip);
        context.publishEvent(new LoginSuccessEvent(sysUserInfo.getUId(),sysUserInfo.getUsername()));
        return sysUserInfo;
    }

    @Override
    public void updateLoginData(Long uid, String ip) {
        userMapper.updateLoginDataByUserId(uid,ip);
    }
}
